import classNames from "classnames";
import React, { useContext } from "react";
import { ThemeContext } from "../theme";
import { Edit } from "@ct0/icons";
import { createUseStyles } from "react-jss";
import Row from "./components/Row";
import type { ItemComponent, BaseItemType, DescriptionProps } from "./type";

export default Description;

export const useStyles = createUseStyles({
  fontSize: {
    fontSize: (props: { fontSize: number }) => props.fontSize,
  },
});

const DefaultNS = Symbol("default");

const InjectedComponents: Record<symbol, Record<string, any>> = {
  [DefaultNS]: {},
};

function grouping<T>(items: Array<T>, size: 1 | 2 | 3): Array<Array<T>> {
  const group: Array<Array<T>> = [];
  let row: Array<T> = [],
    c = size;
  for (const i of items) {
    row.push(i);
    c--;
    if (c == 0) {
      group.push(row);
      row = [];
      c = size;
    }
  }
  if (row.length) group.push(row);

  return group;
}

function Description<ItemType extends BaseItemType>({
  items = [],
  bordered,
  columns = 1,
  columnGap = 0,
  title,
  style,
  labelWidth,
  namespace = DefaultNS,
  onEdit,
  emptyValueText,
}: DescriptionProps<ItemType>) {
  const { fontSize } = useContext(ThemeContext);
  const classes = useStyles({ fontSize });

  const rows = grouping(items, columns);

  const ns = InjectedComponents[namespace];

  return (
    <div
      style={style}
      className={classNames(
        "ct0-description-container",
        classes.fontSize,
        bordered && "ct0-description-bordered"
      )}
    >
      {title && (
        <div className="ct0-description-title">
          {title}
          {onEdit && (
            <span
              className="ct0-description-edit-icon"
              onClick={(e) => {
                e.stopPropagation();
                onEdit();
              }}
            >
              <Edit />
            </span>
          )}
        </div>
      )}
      <div className="ct0-description">
        {rows.map((i, index) => (
          <Row
            row={i}
            labelWidth={labelWidth}
            key={index}
            columns={columns}
            columnGap={columnGap}
            isLastRow={index == rows.length - 1}
            namespace={ns}
            emptyValueText={emptyValueText}
          />
        ))}
      </div>
    </div>
  );
}

Description.extend = (type: string, component: ItemComponent) => {
  extend(type, component, DefaultNS);
};

Description.new = instance;

function extend(
  type: string,
  component: ItemComponent,
  namespace: symbol = DefaultNS
) {
  const ns = InjectedComponents[namespace];
  if (ns[type]) {
    throw Error(`Description 组件中类型 ${type} 的已存在，无法重复添加`);
  }
  ns[type] = component;
}

function instance<ItemType extends BaseItemType>(namespace?: string) {
  const sym = Symbol(namespace);

  InjectedComponents[sym] = {};

  const innerExtend = (type: string, component: ItemComponent) =>
    extend(type, component, sym);

  const innerDescription = (props: DescriptionProps<ItemType>) => (
    <Description {...props} namespace={sym} />
  );

  return {
    extend: innerExtend,
    Description: innerDescription,
  };
}
